/*
* @Author: slp
* @Date:   2018-05-23 14:27:40
* @Last Modified by:   slp
* @Last Modified time: 2018-05-23 16:06:47
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define IMP_SPECCTLR_EL3 "S3_6_C15_C15_0"
#define IMP_SPECCTLR_EL2 "S3_4_C15_C15_0"
#define IMP_SPECCTLR_EL1 "S3_1_C15_C15_0"

// #define IMP_SPECCTLR(NS/S) P15,1,c9,c0,2
#define IMP_SPECCTLR "P15,1,c9,c0,2"
#define IMP_HSPECCTLR "P15,1,c9,c0,3"

// register bit position map
#define LOCK_BIT 31
#define TE_BIT 20
#define DS_BIT 0
#define LS_BIT 1
#define BR_BIT 2
#define SP_BIT 3

// IMP_SPECCTLR_EL1 register map
#define EL0_DS_BIT 10
#define EL0_LS_BIT 11
#define EL0_BR_BIT 12
#define EL0_SP_BIT 13

#define ENABLE     1
#define DISAABLE   0


static void read_imp_specctlr_el3()
{
	long val = 0;
	asm("mrs %0, "IMP_SPECCTLR_EL3"":"=r"(val));
	printf("read register IMP_SPECCTLR_EL3: 0x%08x\n", val);
}

static void read_imp_specctlr_el2()
{
	long val = 0;
	// asm("mrs %0, "#IMP_SPECCTLR_EL2"":"=r"(val));
	printf("read register IMP_SPECCTLR_EL2: 0x%08x\n", val);
}

static void read_imp_specctlr_el1()
{
	long val = 0;
	// asm("mrs %0, "#IMP_SPECCTLR_EL1"":"=r"(val));
	printf("read register IMP_SPECCTLR_EL1: 0x%08x\n", val);
}

static void write_imp_specctlr_el3(unsigned long val)
{
	printf("write register IMP_SPECCTLR_EL3: 0x%08x\n", val);
	// asm("msr "#IMP_SPECCTLR_EL3", %0": :"r"(val));
}

static void write_imp_specctlr_el2(unsigned long val)
{
	printf("write register IMP_SPECCTLR_EL2: 0x%08x\n", val);
	// asm("msr "#IMP_SPECCTLR_EL2", %0": :"r"(val));
}

static void write_imp_specctlr_el1(unsigned long val)
{
	printf("write register IMP_SPECCTLR_EL1: 0x%08x\n", val);
	// asm("msr "#IMP_SPECCTLR_EL1", %0": :"r"(val));
}

// spr
// spr w1 val
// spr w2 val
// spr w3 val
int main(int argc, char * const argv[]) {
	unsigned long val;
	if (argc == 1) {
		// read all
		read_imp_specctlr_el1();
		read_imp_specctlr_el2();
		read_imp_specctlr_el3();
	}else if(argc == 3){
		// write 
		val = strtoul(argv[2], NULL, 16);
		if(strcmp(argv[1], "w1") == 0){
			write_imp_specctlr_el1(val);
		}else if(strcmp(argv[1], "w2") == 0){
			write_imp_specctlr_el2(val);
		}else if(strcmp(argv[1], "w3") == 0){
			write_imp_specctlr_el3(val);
		}else{
			return -1;
		}
	}else{
		return -2;
	}
    return 0;
}
